home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_c / mikecom / async.asm < prev    next >
Assembly Source File  |  1987-06-04  |  30KB  |  683 lines

  1.  
  2. title INTERRUPT DRIVEN ASYNC FOR MSC
  3. page 75,132
  4.  
  5. ;                 Mike Dumdei,  6 Holly Lane,  Texarkana TX  75503
  6. ;                   Version: 5-13-87
  7.  
  8. comment |======================================================================
  9. This is the main module for the async routines and provides the basic functions
  10. necessary to perform serial I/O  -- open/close ports, send/receive, and the
  11. interrupt handlers.  Async_open makes a call to the MicroSoft C library
  12. function '_malloc' and the close function calls '_free' to dynamically allocate
  13. memory for the rx/tx ring buffers, therefore you must either use the MSC
  14. library when linking or provide your own routines for these functions.
  15. ==============================================================================|
  16.  
  17. include casmhdr.h
  18. defseg          COMM_TEXT
  19. include async.h                         ;define segments, equates, & macros
  20.  
  21. IMPORT_NEAR     <__ck_port_arg, __convert_bpds, __set_bpds>
  22. ifdef FARCODE
  23. IMPORT_FAR      <_malloc, _free>
  24. else
  25. IMPORT_NEAR     <_malloc, _free>
  26. endif                                  ;import external functions
  27.  
  28.  
  29. _DATA           segment
  30.  
  31. ifdef LITES
  32. include         lites1.inc              ;debug data if using onscreen RX/TX ind
  33. endif
  34.  
  35. ;---- Table of pointers to com port data structures
  36. public          __port_dta_tbl
  37. __port_dta_tbl  dw      ofDG com1_dta   ;table used to point SI to appropriate
  38.                 dw      ofDG com2_dta   ;com port data structure
  39.  
  40. ;---- Com data structures for each port, initialized variables in order are:
  41. ;     the segment & offset of the int hdlr, the int vctr nmbr assoc with the
  42. ;     COM port, and the mask to enable the IRQ on the int cntrlr chip
  43. com1_dta        port_dta   <,TXT,ofTXT int_hdlr1,0ch,0efh>
  44. com2_dta        port_dta   <,TXT,ofTXT int_hdlr2,0bh,0f7h>
  45.  
  46. ;---- Interrupt handler vectors and pointer to interrupt loop routine
  47. intrpt_tbl      dw      ofTXT msr_intrpt
  48.                 dw      ofTXT tx_intrpt
  49.                 dw      ofTXT rx_intrpt
  50.                 dw      ofTXT lsr_intrpt
  51. intrpt_lp_adr   dw      ofTXT intrpt_loop
  52.  
  53. _DATA           ends
  54.  
  55.  
  56. begseg          COMM_TEXT
  57.  
  58. ;******************************************************************************
  59. ; ASYNC_OPEN -- Opens a comm port for use.  Returns R_OK if successful else
  60. ;  returns error code.
  61. ;******************************************************************************
  62. ;------------------------------------------------------------------------------
  63. ; This first section of the routine checks the arguments passed to the call
  64. ; for validity and converts them to usable form, initializes the data struc-
  65. ; ture for that port, and allocates space for the transmit and receive buffers.
  66. ;------------------------------------------------------------------------------
  67. publicproc      _async_open
  68.         push    bp
  69.         mov     bp,sp
  70.         push    si
  71.         push    di              ;stack frame, save reg variables
  72.         push    es
  73.         push    ds
  74.         pop     es              ;save old ES and set ES=DS == DGROUP
  75. ;---- Get port address and init if valid && not already in use
  76.         call    __ck_port_arg   ;rtrns lots of info -- see proc header
  77.         pushf                   ;save return status
  78.         mov     cx,ds           ;save user DS
  79.         mov     ax,bios_dta
  80.         mov     ds,ax
  81.       assume ds:bios_dta
  82.         mov     ax,[bx]         ;get base address of req com port from bios_dta
  83.         mov     ds,cx           ;back to our DS
  84.       assume ds:DGROUP
  85.         popf                    ;restore status of call to __ck_port_arg
  86. ifdef DBUG
  87.         jnc     nxt_test1
  88.         jmp     noporterr
  89. nxt_test1:
  90.         jz      nxt_test2
  91.         jmp     inuseerr
  92. else
  93.         jc      noporterr       ;CY = port arg passed to async_open was bad
  94.         jnz     inuseerr        ;NZ = port has already been opened
  95. endif
  96. nxt_test2:
  97.         or      ax,ax
  98.         je      noporterr       ;no good if BIOS doesn't have base address
  99.         mov     COM_BASE,ax     ;store port base address
  100. ;---- Translate baud-parity-databit-stopbit string to comm chip language
  101.         mov     bx,BPDS_ptr     ;get pointer to b-p-d-s string
  102.         call    __convert_bpds  ;call conversion routine
  103.         or      ax,ax
  104.         jnz     err_exit        ;error if rtn code wasn't 0
  105. ;---- Get size of transmit and receive buffers and allocate memory for them
  106.         mov     ax,Tx_len       ;get size request for transmit buffer
  107.         cmp     ax,MAXBUFSIZE
  108.         ja      arg_err
  109.         cmp     ax,MINTXBUFSIZ
  110.         jb      arg_err         ;make sure within MIN/MAX limits
  111.         mov     TX_SIZE,ax
  112.         mov     TX_FREE,ax      ;init port data variables
  113.         mov     ax,Rx_len       ;get size request for receive buffer
  114.         cmp     ax,MAXBUFSIZE
  115.         ja      arg_err
  116.         cmp     ax,MINRXBUFSIZ
  117.         jb      arg_err         ;make sure within MIN/MAX limits
  118.         mov     RX_SIZE,ax
  119.         mov     RX_FREE,ax      ;init port data variables
  120.         add     ax,Tx_len       ;AX = total bytes of mem to allocate
  121.         push    ax              ;setup for call to C lib's 'malloc'
  122.         call    _malloc         ;allocate the space and get a pointer to it
  123.         add     sp,2
  124. ifdef FARDATA
  125.         mov     cx,ax
  126.         add     cx,dx
  127.         jcxz    memory_err      ;not enough mem if NULL ptr returned
  128. else
  129.         or      ax,ax           ;not enough mem if NULL ptr returned
  130.         jz      memory_err
  131.         mov     dx,ds           ;segment for data in 'near model' is dgroup
  132. endif
  133.         mov     RXTX_SEG,dx     ;save segment addrs of rx/tx buffers
  134. ;---- Finish initialization of the port data structure
  135.         mov     TX_TOP,ax       ;save ptr to start of transmit bufr
  136.         mov     TX_IN,ax
  137.         mov     TX_OUT,ax       ;init transmit buffer to empty condition
  138. ifdef DBUG
  139.         call    dsp_TXIN
  140.         call    dsp_TXOUT
  141. endif
  142.         add     ax,Tx_len       ;calc start of receive bufr
  143.         mov     RX_TOP,ax       ;save ptr to start of receive bufr
  144.         mov     RX_IN,ax
  145.         mov     RX_OUT,ax       ;init receive buffer to empty condition
  146. ifdef DBUG
  147.         call    dsp_RXIN
  148.         call    dsp_RXOUT
  149. endif
  150.         add     ax,Rx_len
  151.         mov     RX_BTM,ax       ;save ptr to last byte of rx bufr + 1
  152.         mov     STATWRD1,0      ;init STAT1 & STAT2 to zero
  153.         mov     STATWRD2,0ff08h ;MSR_NMSK=no MSR flow cntl, TX_STAT=txbuf empty
  154.         jmp s   init_inthndlr
  155.  
  156. ;---- Error exit routines
  157. noporterr:
  158.         mov     ax,R_NOPORT
  159.         jmp s   err_exit
  160. inuseerr:
  161.         mov     ax,R_PORTINUSE
  162.         jmp s   err_exit
  163. arg_err:
  164.         mov     ax,R_BADARG
  165.         jmp s   err_exit
  166. memory_err:
  167.         mov     ax,R_NOMEM
  168. err_exit:
  169.         xor     bx,bx
  170.         mov     COM_BASE,bx     ;show port not in use
  171.         jmp s   opn_exit        ;back to C caller
  172.  
  173. ;----------------------------------------------------------------------------
  174. ; At this point all data to initialize the port has been determined and the
  175. ; port data structure has been initialized.  The next portion of the routine
  176. ; initializes the hardware to the selected parameters and sets up and enables
  177. ; the communication interrupt handling routines.
  178. ;----------------------------------------------------------------------------
  179. ;---- Initialize the communications interrupt handler
  180. init_inthndlr:
  181. ;---- Get and save old interrupt vector
  182.         mov     al,VECTOR_NBR
  183.         mov     ah,35h
  184.         int     21h             ;get current interrupt vector
  185.         mov     OLDVCTR_SEG,es
  186.         mov     OLDVCTR_OFST,bx ;save for when port closed
  187. ;---- Save old value of IER, LSR, and disable 8250 intrpts via the IER
  188.         mov     dx,COM_BASE
  189.         inc     dx              ;xF9)interrupt enable register
  190.         in      al,dx
  191.         jmp s   $+2
  192.         mov     OLD_IER,al      ;save original value of IER
  193.         xor     al,al
  194.         out     dx,al           ;disable all types 8250 intrpts temporarily
  195.         jmp s   $+2
  196.         inc     dx
  197.         inc     dx              ;xFB) line control register
  198.         in      al,dx
  199.         mov     OLD_LCR,al      ;save original value of line contrl register
  200. ;---- Set the new interrupt vector, baud rate, & parity, data, stop bits
  201.         mov     dx,NEWVCTR_OFST
  202.         mov     al,VECTOR_NBR
  203.         push    ds
  204.         mov     ds,NEWVCTR_SEG
  205.         mov     ah,25h
  206.         int     21h             ;set new interrupt vector
  207.         pop     ds
  208.         call    __set_bpds      ;set the baud,parity,data,stop bits, DisIntrprt
  209. ;---- Clear any pending interrupts
  210.         mov     dx,COM_BASE
  211.         add     dx,5            ;xFD) line status register
  212.         in      al,dx           ;clear brk or data error type intrpts
  213.         jmp s   $+2
  214.         sub     dx,5            ;xF8) rx holding register
  215.         in      al,dx           ;read rx register to clr its int status
  216.         jmp s   $+2
  217.         inc     dx
  218.         inc     dx              ;xFA) interrupt id register
  219.         in      al,dx           ;clr tx holding register empty interrupt cond
  220.         jmp s   $+2
  221.         add     dx,4            ;xFE) modem status register
  222.         in      al,dx           ;read MSR to clear chng in stat type intrpts
  223.         mov     MSR_VAL,al      ;save value of MSR
  224.         jmp s   $+2
  225. ;---- Enable RX, LSR, MSR intrpts, save old 8259 mask, & old 8250 MCR value
  226.         dec     dx
  227.         dec     dx              ;xFC) pointing to modem cntrl reg (MCR)
  228.         in      al,dx
  229.         jmp s   $+2
  230.         mov     OLD_MCR,al      ;save orig value of modem control reg
  231. ifdef RTSFALSE
  232.         mov     al,00001001b    ;modem contrl value if RTS is to init'd low
  233. else
  234.         mov     al,00001011b
  235. endif
  236.         out     dx,al           ;enable 8250 com intrpts, set DTR & RTS high
  237.         jmp s   $+2
  238.         sub     dx,3            ;xF9) pointing to intrpt enable reg
  239.         mov     al,00001101b
  240.         out     dx,al           ;enable MSR, LSR, & RX intrpts
  241.         jmp s   $+2
  242.         in      al,IMR_8259
  243.         jmp s   $+2
  244.         mov     ah,MSK_8259
  245.         not     ah
  246.         and     ah,al
  247.         mov     OLD_8259_MSK,ah ;save old 8259 mask for this IRQ #
  248.         and     al,MSK_8259
  249.         out     IMR_8259,al     ;enable 8259 IRQx interrupt
  250. ;---- Finished with initialization
  251.         sti                     ;ready to go
  252.         xor     ax,ax           ;return R_OK
  253. opn_exit:
  254.         pop     es
  255.         pop     di
  256.         pop     si
  257.         pop     bp
  258.         ret                     ;restore regs and exit with r_code
  259. _async_open     endp
  260.  
  261. ;*****************************************************************************
  262. ; ASYNC_CLOSE -- This routine closes an opened communications port.  All data
  263. ; in tx and rx buffers is lost.  Returns R_NOPORT if port nmbr was invalid or
  264. ; already not active.  Returns R_OK if successful.
  265. ;*****************************************************************************
  266. publicproc      _async_close
  267.         push    bp
  268.         mov     bp,sp
  269.         push    si              ;setup stk frame and save register varible
  270.         call    __ck_port_arg   ;check the port arg and load pointers
  271.         jz      async_clsexit   ;return err of invld arg or port not open
  272.         inc     dx              ;xF9) enable interrupt register
  273.         mov     al,OLD_IER
  274.         cli
  275.         out     dx,al           ;restore intrpt enable reg to original cond
  276.         jmp s   $+2
  277.         inc     dx
  278.         inc     dx              ;xFB) line control register (LCR)
  279.         mov     al,OLD_LCR
  280.         out     dx,al           ;restore LCR to orig value
  281.         jmp s   $+2
  282.         inc     dx              ;xFC) modem control register
  283.         mov     al,OLD_MCR
  284.         out     dx,al           ;restore org status of MCR
  285.         jmp s   $+2
  286.         in      al,IMR_8259
  287.         jmp s   $+2
  288.         or      al,OLD_8259_MSK
  289.         out     IMR_8259,al     ;restore IRQx to original condition
  290.         push    ds
  291.         mov     al,VECTOR_NBR
  292.         mov     dx,OLDVCTR_OFST
  293.         mov     ds,OLDVCTR_SEG
  294.         mov     ah,25h
  295.         int     21h             ;restore old interrupt vector
  296.         sti
  297.         pop     ds
  298.         mov     dx,RXTX_SEG     ;seg value of ptr
  299.         mov     ax,TX_TOP       ;offset of ptr returned by call to 'malloc'
  300.         push    dx
  301.         push    ax              ;push both to take care of either mem model
  302.         call    _free
  303.         add     sp,4            ;free mem alloc for RX/TX buffers
  304.         xor     ax,ax           ;return R_OK
  305.         mov     COM_BASE,ax     ;show port inactive
  306. async_clsexit:
  307.         pop     si
  308.         pop     bp
  309.         ret                     ;clean up and exit to C
  310. _async_close    endp
  311.  
  312. ;*****************************************************************************
  313. ; ASYNC_TX -- Gets character passed by C caller and puts it in the transmit
  314. ; buffer.  Returns R_TXERR if no room in bufr or port argument was invalid.
  315. ; Returns number bytes left in buffer if tx was successful.
  316. ;*****************************************************************************
  317. publicproc      _async_tx
  318.         push    bp
  319.         mov     bp,sp
  320.         push    si
  321.         push    es              ;setup stack and save regs
  322.         call    __ck_port_arg   ;ck port argument & load pointers
  323.         mov     ax,R_TXERR
  324.         jz      async_texit     ;bad port if ZR
  325.         cmp     TX_FREE,0
  326.         je      async_texit     ;no good if no place to put input char
  327.         mov     es,RXTX_SEG     ;get seg of rx/tx bufrs
  328.         cli
  329.         mov     bx,TX_IN        ;get ptr to tx bufr input
  330.         mov     al,TxChar       ;get char passed by function call
  331.         mov     es:[bx],al      ;put it in the tx bufr
  332.         inc     bx
  333.         cmp     bx,TX_BTM       ;ck if time to loop buffer
  334.         je      lp_txptr
  335. store_txin:
  336.         mov     TX_IN,bx        ;store new 'tx chars in' pointer
  337. ifdef DBUG
  338.         call    dsp_TXIN
  339. endif
  340.         dec     TX_FREE         ;one less byte available in bufr
  341.         and     TX_STAT,n B_TXEMPTY ;clr the nothing to txmt bit in TX_STAT
  342.         jz      start_tx        ;start txmtr if not on & no flow cntrl actv
  343. get_txfree:
  344.         mov     ax,TX_FREE      ;get number bytes left in bufr
  345. async_texit:
  346.         sti
  347.         pop     es
  348.         pop     si
  349.         pop     bp
  350.         ret                     ;back to C caller
  351. ;---- Following moved here so no jmps taken for most common case (faster)
  352. lp_txptr:
  353.         mov     bx,TX_TOP       ;reset ptr to top of ring buffer
  354.         jmp s   store_txin      ;back to main flow
  355. start_tx:
  356.         call    __tx_inton      ;start transmitter
  357.         jmp s   get_txfree      ;back to main flow
  358. _async_tx       endp
  359.  
  360. ;******************************************************************************
  361. ; ASYNC_RX -- Receive character routine (read a char from rx buffer).  Returns
  362. ; STAT1 as high byte.  Returns '\0' as char read if buffer was empty and sets
  363. ; bit 6 of the STAT1 byte high.  Bits 0-4 of STAT1 only indicate an error has
  364. ; occurred - not that it occurred on the char just read.  Also bits 0-4 error
  365. ; conditions stay set until async_reset is called.
  366. ;  STAT1: 0=rx bufr ovrfl   1=char overrun     2=parity err    3=framing err
  367. ;         4=break intrpt    5=invalid port     6=rx bufr empty 7=no carrier
  368. ;******************************************************************************
  369. publicproc      _async_rx
  370.         push    bp
  371.         mov     bp,sp
  372.         push    si
  373.         push    es              ;C stack frame, save regs
  374.         call    __ck_port_arg   ;ck Port argument and setup pointers
  375.         mov     ax,0010000000000000b ;set invalid port bit just in case
  376.         jz      async_rexit
  377.         cli
  378.         mov     ax,RX_FREE
  379.         sub     ax,RX_SIZE
  380.         je      rxbuf_empty     ;jump if nothing in rx buffer
  381.         mov     bx,RX_OUT       ;ptr to next char to come out of rx bufr
  382.         mov     es,RXTX_SEG     ;get seg of rx buffer
  383.         xor     cx,cx
  384.         mov     cl,es:[bx]
  385.         inc     bx              ;get a char & incrmnt pointer
  386.         cmp     bx,RX_BTM       ;time to close loop on rx bufr?
  387.         je      lp_rxptr        ;loop rx pointer if at bottom
  388. store_rxptr:
  389.         mov     RX_OUT,bx       ;store ptr to next char to get
  390. ifdef DBUG
  391.         call    dsp_RXOUT
  392. endif
  393.         inc     RX_FREE         ;another byte available in rx bufr
  394.         test    STAT2,B_XSENT   ;has an XOFF been sent? (NZ = yes)
  395.         jnz     ckxflow_ctl     ;see if now time to send XON if XOFF was sent
  396. setstat:
  397.         xor     ah,ah           ;not rxempty, not invalid port
  398. setstat2:
  399.         or      ah,STAT1        ;get STAT bits set by RX/MSR intrpt routines
  400.         mov     al,cl           ;AL = char read
  401. async_rexit:
  402.         sti
  403.         pop     es
  404.         pop     si
  405.         pop     bp
  406.         ret                     ;back to C caller
  407. ;---- Following moved here so no jmps taken for most common case (faster)
  408. rxbuf_empty:
  409.         mov     cl,al           ;else set char retrned = '\0',
  410.         mov     ah,B_RXEMPTY    ;set bit showing bufr empty (AH == 40h),
  411.         jmp s   setstat2        ;and go get rest of status information
  412. lp_rxptr:
  413.         mov     bx,RX_TOP       ;loop back to top of bufr if it is
  414.         jmp s   store_rxptr     ;back to main flow
  415. ckxflow_ctl:
  416.         cmp     RX_FREE,XONCOUNT
  417.         jna     setstat         ;jmp if rxbuf to full to send XON yet
  418.         and     STAT2,n B_XSENT ;clr bit that indicates XOFF sent active
  419.         mov     TXIMMEDCHAR,XONCHAR  ;XON will be next char tx'd
  420.         and     TX_STAT,n B_TXEMPTY  ;set bit saying something needs tx'd
  421.         jnz     setstat         ;done if tx alrdy on or other flw halt is actv
  422.         push    cx              ;save char gotten from rx buffer
  423.         call    __tx_inton      ;start the transmitter
  424.         pop     cx
  425.         jmp s   setstat         ;restore char and back to main flow
  426. _async_rx       endp
  427.  
  428. ;****************************************************************************
  429. ; INTERRUPT ROUTINES:
  430. ; This is the interrupt handling routine.  It is called whenever the receive
  431. ; holding register for an active port has a character or when transmitting
  432. ; whenever the transmit hold register for a transmitting port is ready for
  433. ; another character.  Also monitors MSR and LSR interrupts.
  434. ;****************************************************************************
  435. ;---- Entry point for interrupt (BX set to slct appropriate port_dta struc)
  436. int_hdlr2       proc    far
  437.         push    bx                              ;entry if COM2 interrupted
  438.         mov     bx,ofDG __port_dta_tbl+2        ;BX = ptr to ptr to com2_dta
  439.         jmp s   setup_proc
  440. int_hdlr1       proc    far
  441.         push    bx                              ;entry if COM1 interrupted
  442.         mov     bx,ofDG __port_dta_tbl          ;BX = ptr to ptr to com1_dta
  443. ;---- Allow other intrpts, save regs, and init ptrs to DGROUP, port_dta struc,
  444. ;     and rx/tx buffers
  445. setup_proc:
  446.         sti
  447.         push    ax
  448.         push    cx
  449.         push    dx
  450.         push    si
  451.         push    ds
  452.         push    es              ;save registers
  453.         mov     ax,DGROUP
  454.         mov     ds,ax           ;point to our data area
  455.         mov     si,[bx]         ;SI = ptr to appropriate port_dta for this prt
  456.         mov     es,RXTX_SEG     ;get segment where rx/tx bufrs are located
  457. ;---- Main interrupt handling loop.  The loop gets the value in the UART
  458. ;     intrpt ID register and checks the 'intrpt pending bit'.  If the bit
  459. ;     indicates a condition needs servicing the address of the top of the loop
  460. ;     is pushed onto the stack and then a jump is made to the appropriate serv-
  461. ;     ice routine.  When the final 'ret' is encountered in the service routine,
  462. ;     control passes back to the top of this loop.
  463. intrpt_loop:
  464.         mov     dx,COM_BASE     ;DX = COM_BASE (base port address)
  465.         inc     dx
  466.         inc     dx              ;xFA) -- Interrupt ident reg
  467.         in      al,dx
  468.         shr     al,1            ;slide 'pendng bit' into CY & ID bits to 1 & 0
  469.         jc      exit_intrpt     ;done if pending bit indic all intrps processed
  470.         dec     dx
  471.         dec     dx              ;xF8) - back to base register
  472.         push    DG:intrpt_lp_adr  ;this will be return addrs (top of this loop)
  473.         and     ax,0000000000000011b  ;make sure only int status infor is in AX
  474.         shl     ax,1
  475.         mov     bx,ax
  476.         jmp     DG:intrpt_tbl[bx]  ;jmp to the appropriate service routine
  477. ;---- Exit interrupt routine
  478. exit_intrpt:
  479.         cli
  480.         mov     al,20h
  481.         out     ICR_8259,al     ;send 'end of interrupt' to 8259
  482.         pop     es
  483.         pop     ds
  484.         pop     si
  485.         pop     dx
  486.         pop     cx
  487.         pop     ax
  488.         pop     bx              ;restore registers
  489.         iret                    ;exit interrupt
  490. int_hdlr1    endp
  491. int_hdlr2    endp
  492.  
  493. ;---- Interrupt service routine line status register interrupt.
  494. localproc       lsr_intrpt
  495.         add     dx,5            ;xFD) line status register
  496.         in      al,dx           ;reading LSR clears interrupt cond
  497.         and     al,00011110b    ;mask off desired bits
  498.         or      STAT1,al        ;put them in STAT1
  499.         ret                     ;back to interrupt loop
  500. lsr_intrpt      endp
  501.  
  502. ;---- Interrupt service routine for modem status register change.  Used to
  503. ;     keep CD bit in STAT1 updated and as part of CTS, DSR, & CD flow
  504. ;     procedures.
  505. localproc       msr_intrpt
  506.         add     dx,6            ;xFE) modem status register
  507.         in      al,dx           ;reading MSR clears interrupt cond
  508.         mov     MSR_VAL,al      ;store MSR
  509.         mov     ah,al           ;save MSR reg in AH also
  510.         mov     bl,n B_CD
  511.         and     STAT1,bl        ;clr NOT CD bit (!CD) in STAT1 byte
  512.         not     bl
  513.         and     ah,bl           ;mask MSR val to isolate CD bit
  514.         xor     ah,bl           ;invert CD to make it !CD
  515.         or      STAT1,ah        ;update !CD in STAT1 byte
  516.         mov     bx,STATWRD2     ;BH=MSR monitor mask, BL=TX_STAT byte
  517.         and     bl,bh           ;clr monitored bits in TX_STAT
  518.         not     bh
  519.         and     al,bh           ;mask out un-monitored bits in MSR value
  520.         xor     al,bh           ;change monitored bits to their NOT function
  521.         or      al,bl           ;combine updtd monitr bits with TX_STAT
  522.         mov     TX_STAT,al      ;save new TX_STAT
  523.         jnz     msr_exit        ;NZ == tx int running, noth to tx, or flow halt
  524.         jmp     __tx_inton      ;if none of abv is true, time to strt tx bak up
  525. msr_exit:
  526.         ret                     ;back to intrpt loop
  527. msr_intrpt      endp
  528.  
  529. ;---- Interrupt service routine for a 'char received' interrupt.  Received char
  530. ;     is placed in RX bufr unless it is full.  If the bufr is full, char is
  531. ;     ignored and rx bufr ovrflw bit is set in STAT1.  Also performs XON/XOFF
  532. ;     protocol functions and high bit stripping when using those options.
  533. localproc       rx_intrpt
  534.         in      al,dx           ;get char from 8250 hold reg
  535. ifdef LITES
  536.         call    rxlites         ;dsplay debug rx lite if using
  537. endif
  538.         and     al,STRIP_MASK   ;do bit stripping according to strip mask val
  539.         test    STAT2,B_XUSE    ;using XON/XOFF protocol?
  540.         jnz     ck_xchar        ;jmp to ck for XON or XOFF if using protcl
  541. ck_rxfull:
  542.         cmp     RX_FREE,0       ;any room left?
  543.         je      rx_overflow
  544. store_char:
  545.         mov     bx,RX_IN
  546.         mov     es:[bx],al      ;else store the received char
  547.         inc     bx              ;advance bufr pointer
  548.         cmp     bx,RX_BTM       ;is it time to make the circle?
  549.         je      lp_rxptri
  550. store_rxptri:
  551.         mov     RX_IN,bx        ;save new RX_IN ptr
  552. ifdef DBUG
  553.         call    dsp_RXIN
  554. endif
  555.         dec     RX_FREE         ;one less byte avlbl in bufr
  556.         cmp     RX_FREE,XOFFCOUNT  ;bytes free lower than XOFF level?
  557.         jb      ckifneed_XOFFsnt
  558.         ret                     ;done if plenty room in rx buffer
  559. ckifneed_XOFFsnt:
  560.         mov     al,STAT2        ;get STAT2 in AL - several cks on it
  561.         and     al,B_XUSE+B_XSENT ;using XON/OFF? / msk unwanted bits in STAT2
  562.         jnz     send_xoff_ck2
  563.         ret                     ;done if not using XON/OFF prtcl
  564. send_xoff_ck2:
  565.         and     al,B_XSENT
  566.         jz      send_xoff1      ;ZR = XOFF not alrdy sent
  567.         dec     XTXRPT          ;ck if XOFF has been ignored for 'x' # of chars
  568.         jz      send_xoff2      ;send another XOFF if its been ignored
  569.         ret                     ;else back to intrpt loop
  570. send_xoff1:
  571.         or      STAT2,B_XSENT   ;set bit showing XOFF sent
  572. send_xoff2:
  573.         mov     XTXRPT,REPTXOFFVAL ;set up 'ignored' counter
  574.         mov     TXIMMEDCHAR,XOFFCHAR  ;XOFF will be next char tx'd
  575.         and     TX_STAT,n B_TXEMPTY   ;clr bit that indicates nothing to txmt
  576.         jz      __tx_inton      ;strt tx if not alrdy on or other flow hlt actv
  577.         ret                     ;back to interrupt loop
  578. ;---- Following moved out of main line of rx intrpt routn in attempt to get
  579. ;     fastest performance in most likely to occur cases.
  580. rx_overflow:
  581.         or      STAT1,B_RXOVF   ;set bit for rx bufr ovfl if no room
  582.         ret
  583. lp_rxptri:
  584.         mov     bx,RX_TOP
  585.         jmp s   store_rxptri
  586. ck_xchar:
  587.         cmp     al,XOFFCHAR
  588.         je      xoff_rcvd       ;jmp if char was an XOFF
  589.         test    STAT3,B_XONANY
  590.         jnz     ck_xoffactv     ;jmp if any char can be an XON
  591.         cmp     al,XONCHAR      ;was it a real XON?
  592.         jne     ck_rxfull       ;back to main rxintrpt stream if not XON
  593. xon_rcvd:
  594.         and     TX_STAT,n B_XRXD  ;clr bit showing XOFF rx'd
  595.         jz      __tx_inton      ;rstrt tx if something to tx, no othr flw hlt
  596.         ret                     ;back to intrpt loop
  597. ck_xoffactv:
  598.         test    TX_STAT,B_XRXD
  599.         jnz     xon_rcvd        ;clr XOFF if active and any char can be XON
  600.         jmp s   ck_rxfull       ;else treat char as normal char
  601. xoff_rcvd:
  602.         or      TX_STAT,B_XRXD  ;set bit showing XOFF rx'd (will shut dn tx)
  603.         ret                     ;back to intrpt loop
  604. rx_intrpt       endp
  605.  
  606. ;---- This procedure is called to initiate tx interrupts. Falls
  607. ;     into the tx interrupt handler.
  608. localproc       __tx_inton
  609. public          __tx_inton
  610.         mov     dx,COM_BASE
  611.         add     dx,5            ;xFD)line status register
  612. wttxempty:
  613.         in      al,dx
  614.         and     al,00100000b    ;test if tx hold reg is empty
  615.         jz      wttxempty       ;and wait for it to be empty if its not
  616.         jmp s   $+2
  617.         sub     dx,4            ;xF9)intrpt enable register
  618.         in      al,dx           ;get UART interrupt mask
  619.         jmp s   $+2
  620.         or      al,00000010b    ;set TX intrpts bit
  621.         out     dx,al           ;send new mask to the 8250
  622.         or      TX_STAT,B_TXION ;set bit in TX_STAT that says tx intrpts on
  623.         dec     dx              ;xF8) tx hold register
  624. __tx_inton        endp
  625.  
  626. ;---- Interrupt service routine for transmitter ready condition.  This routine
  627. ;     first checks to see if any flow control has been activated and shuts off
  628. ;     tx interrupts if it has.  Next it looks at the TXIMMEDCHAR and if it is
  629. ;     not a null transmits it next otherwise transmits the next buffer char.
  630. localproc       tx_intrpt
  631.         mov     al,FLOW_MASK
  632.         and     al,TX_STAT
  633.         jnz     __shutoff_tx    ;shutoff tx'r if XOFF, !CTS, !DSR, or !CD actv
  634.         xor     al,al
  635.         xchg    al,TXIMMEDCHAR
  636.         or      al,al           ;ck if TXIMMED was a null & clr it for nxt time
  637.         jnz     txi_char        ;jmp if TXIMMED
  638.         mov     ax,TX_SIZE
  639.         cmp     ax,TX_FREE
  640.         je      nomore_tx       ;jmp if nothing left to transmit
  641.         mov     bx,TX_OUT       ;pointer to next buf char to transmit
  642.         mov     al,es:[bx]      ;get tx buffer character
  643.         inc     TX_FREE         ;updt tx free bufr space value
  644.         inc     bx
  645.         cmp     bx,TX_BTM
  646.         jne     updt_txptr
  647.         mov     bx,TX_TOP
  648.         jmp s   $+2
  649. updt_txptr:
  650.         mov     TX_OUT,bx       ;update the tx buffer pointer
  651. ifdef DBUG
  652.         call    dsp_TXOUT
  653. endif
  654. txi_char:
  655.         out     dx,al           ;send the character
  656. ifdef LITES
  657.         call    txlites
  658. endif
  659.         ret                     ;else finished with tx routine
  660. nomore_tx:
  661.         or      TX_STAT,B_TXEMPTY  ;set bit showing nothing to tx
  662. localproc       __shutoff_tx
  663. public          __shutoff_tx
  664.         inc     dx              ;xF9) interrupt enable register
  665.         in      al,dx
  666.         jmp s   $+2
  667.         and     al,00001101b
  668.         out     dx,al           ;mask tx interrupt bit off in 8250
  669.         and     TX_STAT,n B_TXION ;clr bit in TX_STAT that indic tx is on
  670.         ret                     ;finished
  671. __shutoff_tx    endp
  672. tx_intrpt       endp
  673.  
  674. ifdef DBUG
  675. include         dbug.inc            ;display ring bufr ptr values debug code
  676. endif
  677. ifdef LITES
  678. include         lites2.inc          ;onscreen rx/tx indicator code
  679. endif
  680.  
  681. endseg          COMM_TEXT
  682.                 end
  683.